package com.oocl.im.handler;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.oocl.im.pojo.MsgPackage;
import com.oocl.im.pojo.Operation;
import com.oocl.im.util.JsonUtil;

public class ChatHandler implements Runnable {
	private String name;
	private Socket socket;
	private BufferedReader reader;
	private PrintWriter writer;
	private HashMap<String, ChatHandler> handlerPool;

	public ChatHandler(String name, Socket socket,
			HashMap<String, ChatHandler> handlerPool) {
		super();
		this.name = name;
		this.socket = socket;
		try {
			this.reader = new BufferedReader(new InputStreamReader(
					socket.getInputStream()));
			this.writer = new PrintWriter(socket.getOutputStream(), true);
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.handlerPool = handlerPool;
	}

	@Override
	public void run() {
		String msgJson = null;
		MsgPackage msg = null;
		try {
			System.out.println("notify");
			notify2();
			while (true) {
				msgJson = reader.readLine();
				msg = JsonUtil.stringToObject(msgJson);
				switch (msg.getOpeartion()) {
				case CHAT:
					chat(msg);
					break;
				case SHAKE:
					shake(msg);
					break;
				case EXIT:
					exit(msg);
					return;
				default:
					break;
				}
			}

		} catch (SocketException E) {
			synchronized (handlerPool) {
				handlerPool.put(name, null);
			}
			try {
				notify2();
				socket.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(name + " exit");
		} catch (Exception e) {
			e.printStackTrace();
			synchronized (handlerPool) {
				handlerPool.put(name, null);
			}
			try {
				notify2();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}

	public void exit(MsgPackage msg) throws Exception {
		String sender = msg.getSender();
		System.out.println(sender + " exit");
		synchronized (handlerPool) {
			handlerPool.put(sender, null);
		}
		notify2();
		socket.close();
	}

	public void shake(MsgPackage msg) throws Exception {
		String receiver = msg.getReceiver();
		if (msg.getReceiver().equals("all")) {
			System.out.println("cannot shake all people");
		} else {
			synchronized (handlerPool) {
				ChatHandler h = handlerPool.get(receiver);
				if (h != null) {
					String msgJson = JsonUtil.objectToString(msg);
					h.writer.println(msgJson);
				}
			}
		}
	}

	public void chat(MsgPackage msg) throws Exception {
		String sender = msg.getSender();
		String receiver = msg.getReceiver();
		if ("all".equals(receiver)) {
			synchronized (handlerPool) {
				for (Map.Entry<String, ChatHandler> entry : handlerPool
						.entrySet()) {
					boolean on = entry.getValue() != null;
					boolean isSelf = entry.getKey().equals(sender);
					if (on && !isSelf) {
						String msgJson = JsonUtil.objectToString(msg);
						entry.getValue().writer.println(msgJson);
					}
				}
			}
		} else {
			synchronized (handlerPool) {
				ChatHandler h = handlerPool.get(receiver);
				if (h != null) {
					String msgJson = JsonUtil.objectToString(msg);
					h.writer.println(msgJson);
				}
			}
		}
	}

	/**
	 * notiy2 mean notify all online user about online info of users
	 * 
	 * @throws Exception
	 */
	public void notify2() throws Exception {
		synchronized (handlerPool) {
			HashMap<String, Boolean> hasLoginMap = new HashMap<>();
			hasLoginMap.put("all", true);
			for (Entry<String, ChatHandler> entry : handlerPool.entrySet()) {
				if (entry.getValue() == null) {
					hasLoginMap.put(entry.getKey(), false);
				} else {
					hasLoginMap.put(entry.getKey(), true);
				}
			}
			MsgPackage msg = new MsgPackage(Operation.NOTIFY, null, null, null,
					null, hasLoginMap);
			for (Entry<String, ChatHandler> entry : handlerPool.entrySet()) {
				if (entry.getValue() != null) {
					String msgJson = JsonUtil.objectToString(msg);
					System.out.println(msgJson);
					entry.getValue().writer.println(msgJson);
				}
			}
		}

	}
}